// { dg-do compile { target c++11 } }

template<typename T, typename U> 
struct is_same 
{
  static const bool value = false;
};

template<typename T>
struct is_same<T, T>
{
  static const bool value = true;
};

#define CHECK_DECLTYPE(DECLTYPE,RESULT) \
  static_assert(is_same< DECLTYPE , RESULT >::value, #DECLTYPE " should be " #RESULT)

class A { 
public:
  int a; 
  int& b; 
  static int c; 

  A(int& b) : b(b) { }

  void foo() { 
    CHECK_DECLTYPE(decltype(a), int);
    CHECK_DECLTYPE(decltype(this->a), int);
    CHECK_DECLTYPE(decltype((*this).a), int);
    CHECK_DECLTYPE(decltype(b), int&);
    CHECK_DECLTYPE(decltype(c), int);
  } 
  void bar() const {
    CHECK_DECLTYPE(decltype(a), int);
    CHECK_DECLTYPE(decltype(b), int&);
    CHECK_DECLTYPE(decltype(c), int);
  } 
}; 

int b;
A aa(b); 
const A& caa = aa; 
CHECK_DECLTYPE(decltype(aa.a), int);
CHECK_DECLTYPE(decltype(aa.b), int&);
CHECK_DECLTYPE(decltype(caa.a), int);

class B { 
public:
  int a;
  enum B_enum { b }; 
  decltype(a) c;
  decltype(a) foo() { return 0; }
  decltype(b) enums_are_in_scope() { return b; } // ok 
}; 

CHECK_DECLTYPE(decltype(aa.*&A::a), int&);
decltype(aa.*&A::b) zz; // { dg-error "18:cannot create pointer to reference member" "cannot" }

CHECK_DECLTYPE(decltype(caa.*&A::a), const int&);

class X { 
  void foo() { 
    CHECK_DECLTYPE(decltype(this), X*);
    CHECK_DECLTYPE(decltype(*this), X&);
  } 
  void bar() const { 
    CHECK_DECLTYPE(decltype(this), const X*);
    CHECK_DECLTYPE(decltype(*this), const X&);
  } 
};

